package core.module
{
import core.Configuration;
import core.log.GameLogType;
import core.log.GameLogger;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.Dictionary;

import framework.core.AssetsManager;
import framework.core.UIWidget;
import framework.view.components.graphics.Asset;
import framework.view.components.graphics.SWF;

import values.module.ModuleSkinValue;
import values.module.ModuleValue;
import values.module.ModuleValueList;

/**
 * ModuleManager
 * @author jliang
 * 
 */
public class ModuleManager extends EventDispatcher implements IModuleManager
{
    //==========================================================================
    //  Class constants
    //==========================================================================
    public static function load(key:String, callBack:Function):void
    {
        var mvo:ModuleValue = ModuleValueList.getByKey(key);
        GameLogger.log(GameLogType.MODULE_REQUEST, mvo, callBack);
    }    
	//==========================================================================
	//  Constructor  single modle
	//==========================================================================
	public function ModuleManager()
	{
		super();
	}
	//==========================================================================
	//  Variables
	//==========================================================================
	private var modules:Dictionary = new Dictionary(true);  /* ModuleObject */
	
	private var queen:Vector.<ModuleObject> = new Vector.<ModuleObject>();
	
	private var registedSkin:Dictionary = new Dictionary(true);  /* Boolean */
	
	private var loadingModule:ModuleObject;
	//==========================================================================
	//  Public methods
	//==========================================================================
	public function initialize():void
	{
		
	}
	
	public function checkGameAction(type:String, ...args):void
	{
		var obj:ModuleObject;
		if (type == GameLogType.MODULE_REQUEST)
		{			
			if (loadingModule)
			{
				obj = new ModuleObject();			
				obj.data = args[0];
				obj.readyCallBack = args[1];
				obj.params = args[2] ? args.splice(2) : [];
				
				queen.push(obj);
				return;
			}
			else
			{				
				var params:Array = [].concat(args);
				if (params.length == 1)
				{
					params[1] = null;
				}
				requestModule.apply(this, params);
			}			
			return;
		}
		
		obj = null;
		for each (obj in modules)
		{
			if (!obj.content || !obj.content.isInited) continue;
			obj.content.checkGameAction.apply(obj.content, [ type ].concat(args));
		}
	}
	
	private function requestModule(data:ModuleValue, readyCallBack:Function, ...args):void
	{
		var obj:ModuleObject = modules[data.key];
		if (!obj)
		{
			obj = new ModuleObject();
		}
		obj.data = data;
		obj.params = args;
		obj.readyCallBack = readyCallBack;
		obj.skinCount = 0;
		
		loadingModule = obj;
		
		if (loadingModule == modules[data.key])
		{
			initModule(loadingModule.classRef, loadingModule);
			return;
		}
		modules[data.key] = obj;
		
		if (data.skins.length > 0)
		{
			for each (var skin:ModuleSkinValue in data.skins)
			{
				AssetsManager.loadAsset(Configuration.assetsPath + skin.url, skinLoadedHandler);
			}
		}
		else
		{
			AssetsManager.loadSWFAsset(loadingModule.data.url, SWF.MODULE, moduleLoadedHandler, moduleErrorHandler);	
		}
	}
	
	private function skinLoadedHandler(asset:Asset):void
	{
		loadingModule.skinCount ++;
		
		if (asset is SWF) 
		{
			if (registedSkin[asset.url] != true) 
			{
				UIWidget.registerAppDomain(SWF(asset).appDomain);
				registedSkin[asset.url] = true;
			}
		}
		
		if (loadingModule.skinCount >= loadingModule.data.skins.length)
		{
			AssetsManager.loadSWFAsset(loadingModule.data.url, SWF.MODULE, moduleLoadedHandler, moduleErrorHandler);	
		}
	}
	
	private function moduleLoadedHandler(asset:SWF):void
	{		
		var ref:Class = asset.getClassRef(loadingModule.data.classRef);
		
		asset.dispose();
		asset = null;
		
		loadingModule.classRef = ref;
		initModule(ref, loadingModule);
	}
	
	private function initModule(ref:Class, holder:ModuleObject):void
	{
		var content:IGameModule = new ref() as IGameModule;
		holder.content = content;
		
		content.addEventListener(Event.INIT, moduleInitCompleteHandler);
		content.addEventListener(Event.CLOSE, moduleDisposedHandler);
		content.initialize.apply(loadingModule.content, loadingModule.params ? [ loadingModule.data ].concat(loadingModule.params) : [ loadingModule.data ]);
	}
	
	private function moduleInitCompleteHandler(event:Event):void
	{
		event.target.removeEventListener(Event.INIT, moduleInitCompleteHandler);
		
		if (loadingModule.readyCallBack != null)
		{
			loadingModule.readyCallBack(event.target);
		}
		
		GameLogger.log(GameLogType.MODULE_INITED, loadingModule.data);
		
		loadingModule.params = null;
		loadingModule.readyCallBack = null;
		loadingModule.skinCount = 0;
		
		loadingModule = null;
		
		if (queen.length > 0)
		{
			var obj:ModuleObject = queen.shift();
			requestModule.apply(this, [ obj.data, obj.readyCallBack ].concat(obj.params));
		}
	}
	
	private function moduleDisposedHandler(event:Event):void
	{
		event.target.removeEventListener(Event.CLOSE, moduleDisposedHandler);
		var obj:ModuleObject = modules[IGameModule(event.target).data.key];
		
		GameLogger.log(GameLogType.MODULE_DISPOSED, obj.data);
		
		obj.content = null;
	}
	
	private function moduleErrorHandler(asset:SWF):void
	{
		trace("Module load failed. " + asset.url);
	}
}
}
import core.module.IGameModule;

import framework.view.components.graphics.SWF;

import values.module.ModuleValue;

class ModuleObject
{	
	public var data:ModuleValue;
	
	public var classRef:Class;
	
	public var params:Array;
	
	public var content:IGameModule;
	
	public var readyCallBack:Function;
	
	public var skinCount:int = 0;
}


